from celery import shared_task

import logging
from django.db.models import Avg, Max, Min, Count, Sum  #   引入函数
from datetime import datetime, date, timedelta
from iClouds.apidev import hash_md5, hash_name, hash_time, has_Random
from mysqldb.models import (
    FsygMemberLevel,
    AllinpayProgrunList,
    AllinpayPlaceList,
    FsygMemberList,
    FsygProgrunList,
    AllinpayMemberList,
    AllinpayHardwareList,
)
from mysqldb import redis as REDIS
from mysqldb.redis import clear_dict
from MoniterManager.tasks import doMoniterPulsarScreen

logger = logging.getLogger(__name__)


@shared_task
def UpDownEventFromFsygChange(data):
    """凡商易购换机处理 (换机信息 1.6)"""
    try:
        r = AllinpayProgrunList.objects.get(
            message_type="upmachine",
            carid=data.get("from_card_id"),
            computer_name=data.get("from_computer"),
        )
    except BaseException as err:
        logger.warn(f"[machine_change] [未找到原始上机记录] {data}")
    else:
        r.computer_name = data.get("to_computer")
        r.save()
    return {"rescode": 200, "resmsg": "success"}


@shared_task
def UpDownEventFromFsygPay(pid, data):
    """凡商易购结算处理 (用户信息 2.2)"""
    # ---------------------------------------------
    # 开始处理
    # ---------------------------------------------
    ulist = data.get("data", {}).get("body", [])
    for i in ulist:
        info = i.copy()
        # 检查会员
        try:
            v = AllinpayMemberList.objects.get(idcode=info.get("id_card"), pid=pid)
        except BaseException as err:
            logger.warn(f"[cqbar] [{pid}]  下机查询会员失败 {err} {data}")
        else:
            v.overage = info.get("overage")
            v.reward = info.get("reward")
            v.integral = info.get("usable_integral")
            v.save()
    return {"rescode": 200, "resmsg": "success"}


@shared_task
def UpDownEventFromFsygOff(pid, data):
    """凡商易购下机处理 (下机推送 1.5)"""

    def doWriteRedis(pid, name, dbs):
        """写入缓存"""
        dbs = REDIS.clear_dict(dbs)
        key = f"{pid}--{name}"
        REDIS.redis_del("workStatus", key)
        REDIS.redis_hash_set("workStatus", key, dbs)

    # ---------------------------------------------
    # 开始处理
    # ---------------------------------------------
    # 创建公共数据
    hostname, area, midcode = "", "", ""
    try:
        res = AllinpayProgrunList.objects.get(
            pid=pid,
            computer_name=data["computer_name"],
            carid=data["card_id"],
            message_type="upmachine",
        )
    except BaseException as err:
        logger.warn(f"[cqbar] [{pid}] 下机查询在线记录失败 {err} {data}")
    else:
        res.message_type = "downmachine"
        res.amount = int(float(data.get("amount")) * 100)
        res.down_day = datetime.strptime(
            data.get("down_time"), "%Y-%m-%d %H:%M:%S"
        ).date()
        res.down_time = datetime.strptime(data.get("down_time"), "%Y-%m-%d %H:%M:%S")
        res.save()
        hostname = res.computer_name
        area = res.computer_area
        midcode = res.carid

    # 检查会员
    try:
        v = AllinpayMemberList.objects.get(idcode=midcode, pid=pid)
    except BaseException as err:
        logger.warn(f"[cqbar] [{pid}]  下机查询会员失败 {err} {data}")
        # raise ValueError(f"[cqbar] 查询会员失败 {err}")
    else:
        # 计算本次上机时长
        timelen = (res.down_time - res.up_time).minutes
        # 计算统计数据
        v.accummoney = v.accummoney + int(float(data.get("amount")) * 100)  # 累计消费金额 (分)
        v.accumtime = v.accumtime + timelen  # 累计上机时长 (分钟)
        # v.overage = 0 #int(float(data.get("balance")) * 100)  # 当前余额 (分)
        v.save()

    if hostname:
        # 创建数据
        dbs = {
            "status": 2,  # 终端状态 0维修，1上机中，2待清洁，3待机中
            "localhost": hostname,  # 终端机号
            "group": area,
            "ipaddr": None,
            "mask": None,
            "gateway": None,
            "currenttime": data.get("end_time"),
        }
        # 写入缓存
        doWriteRedis(pid, hostname, dbs)
        # # 创建下机清理
        from fsygManager.tasks import CreateCallmeClearReqsn

        callme = CreateCallmeClearReqsn(pid, hostname)
        # # 发送消息队列pulsar
        r = doMoniterPulsarScreen(f"{pid}", dbs)
    return {"rescode": 200, "resmsg": "success"}


@shared_task
def UpDownEventFromFsygOnn(pid, data):
    """凡商易购上机处理 (上机信息 2.1)"""

    def doWriteRedis(pid, name, dbs):
        """写入缓存"""
        dbs = REDIS.clear_dict(dbs)
        key = f"{pid}--{name}"
        REDIS.redis_del("workStatus", key)
        REDIS.redis_hash_set("workStatus", key, dbs)

    def has_guid(pid, pcname, uptime):
        """计算上机时间"""
        guid = f"{uptime}{pcname}{pid}"
        return hash_md5(guid)

    def has_Member_Level(wbid, name):
        """查询会员等级"""
        try:
            r = FsygMemberLevel.objects.get(wbcode=wbid, name=name)
        except BaseException as err:
            return 1
        else:
            return r.level

    def to_Count_Week(wbid, cardid):
        """统计每周会员次数"""
        week = date.today().weekday()
        sd = date.today() - timedelta(days=week)
        ed = sd + timedelta(days=7)
        c = AllinpayProgrunList.objects.filter(
            pid=wbid, carid=cardid, on_day__range=(sd, ed)
        ).aggregate(cishu=Count("id"))
        return c.get("cishu", 0)

    # ---------------------------------------------
    # 开始处理
    # ---------------------------------------------
    ulist = data.get("data", {}).get("body", [])
    for i in ulist:
        info = i.copy()
        tt = hash_time(info.get("up_timestamp"))
        # 检查会员
        v, faq = AllinpayMemberList.objects.update_or_create(
            defaults={
                "name": hash_name(info.get("user_name")),
                "lasttime": tt,
                "level": info.get("user_level"),
                "hash": info.get("guid"),
            },
            idcode=info.get("id_card"),  # hash_md5(info.get("id_card").upper()),
            pid=pid,
        )
        if faq:
            v.creattime = tt
            v.gender = 0
            v.overage = 0
            v.reward = 0
            v.integral = 0
            v.accummoney = 0
            v.accumtime = 0
            v.save()
            logger.info(f"[cqbar] [{pid}] 创建新会员 {v.id}")

        # 检查终端
        p, fap = AllinpayHardwareList.objects.update_or_create(
            defaults={
                "lasttime": tt,
                "ipaddr": info.get("computer_ip"),
                "mac": info.get("computer_mac"),
            },
            pcname=info.get("computer_name"),
            pid=pid,
        )
        if fap:
            p.status = 1
            p.save()

        # 上机记录
        guid = has_guid(pid, p.pcname, info.get("up_timestamp"))
        r, far = AllinpayProgrunList.objects.update_or_create(
            defaults={
                "message_type": "upmachine",
                "carid": v.idcode,
                "computer_name": p.pcname,
                "computer_area": p.area,
                "pid": pid,
                "on_day": v.lasttime.date(),
                "on_time": v.lasttime,
                "bem": "凡商易购",
            },
            guid=guid,
        )
        # 统计数据
        try:
            dc = to_Count_Week(data.get("wb_id"), data.get("card_id")) + 1
        except BaseException as err:
            dc = 1
        dbs = {
            "status": 1,
            "localhost": p.pcname,  # 终端机号
            "group": p.area,
            "ipaddr": p.ipaddr,
            "mask": "",
            "gateway": "",
            "currenttime": v.lasttime.strftime("%Y-%m-%d %H:%M:%S"),
            "hash": v.idcode,
            "guid": guid,
            "gender": v.gender,  # random.choice(range(2)),
            "level": has_Member_Level(pid, data.get("cn_account_level")),
            "member": {
                "name": v.name,
                "code": "",
                "hash": v.idcode,
                "phone": v.phone,
                "birthday": v.birthday,
                "gender": v.gender,
                "openid": v.openid,
                "registtime": str(v.creattime),
                "lasttime": str(v.lasttime),
                "level": v.level,
                "overage": v.overage,
                "reward": v.reward,
                "integral": v.integral,
                "accummoney": v.accummoney,
                "accumtime": v.accumtime,
            },
            "Count": {
                "money": v.accummoney,
                "domoney": 0,
                "timelong": v.accumtime,
                "dolong": 0,
                "week": dc,
            },
        }
        # # 写缓存
        doWriteRedis(pid, p.pcname, dbs)
        # # 发送消息队列pulsar
        r = doMoniterPulsarScreen(f"{pid}", dbs)
    return {"rescode": 200, "resmsg": "success"}


@shared_task
def MemberLevelCountTasks(rule):
    def has_wb_id(pid):
        try:
            r = AllinpayPlaceList.objects.get(id=pid)
            return r.barcode
        except Exception as e:
            return None

    def SelectFsygMemberListFromWeek(rule):
        """查询周频率"""
        f = {}
        if rule.get("pid"):
            wbid = has_wb_id(rule.get("pid"))
            f["wb_id"] = wbid
        if rule.get("week"):
            target_date = date.today() - timedelta(days=7)
            f["on_day__gte"] = target_date
        r = (
            FsygProgrunList.objects.filter(**f)
            .values("card_id")
            .annotate(a=Count("card_id"))
            .filter(a__gte=rule.get("week"))
            .values_list("card_id", flat=True)
        )
        return list(r)

    def SelectFsygMemberListFromOther(rule):
        """其他查询条件"""
        if rule.get("lol"):
            pass
        if rule.get("csgo"):
            pass
        if rule.get("steam"):
            pass
        if rule.get("other"):
            pass
        if rule.get("week"):
            pass
        return None

    def SelectFsygMemberListFromDate(rule):
        """查询会员列表"""
        f = {}
        if rule.get("pid"):
            wbid = has_wb_id(rule.get("pid"))
            f["wb_id"] = wbid
        if rule.get("lastreg"):
            target_date = date.today() - timedelta(days=rule.get("lastreg"))
            f["currentdate__gte"] = target_date
        if rule.get("onpay"):
            target_date = date.today() - timedelta(days=rule.get("onpay"))
            f["lasttime__lte"] = target_date
        if rule.get("week"):
            f["codeid__in"] = SelectFsygMemberListFromWeek(rule)

        # print(f)

        r = FsygMemberList.objects.filter(**f).values(
            "id",
            "wb_id",
            "codeid",
            "nicename",
            "bashname",
            "gender",
            "birthday",
            "phone",
            "level",
            "overage",
            "currentdate",
            "lasttime",
            "accumtime",
            "accummoney",
        )
        return r

    # 开始工作
    x = SelectFsygMemberListFromDate(rule)

    return {"rescode": 200, "resmsg": f"{clear_dict(list(x))}", "status": "success"}
